package ru.passivemoney.manage.account;

import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.Currency;

import com.dukascopy.api.Instrument;

//TODO: review AccountHolder class
public class AccountHolder {
	private static final MathContext MC = MathContext.DECIMAL128;
	
	private static Currency currency = Instrument.EURUSD.getPrimaryCurrency(); // TODO: set null
	
	private static BigDecimal margin = BigDecimal.ZERO;
	
	public static void addMarging(BigDecimal margin){
		AccountHolder.margin = AccountHolder.margin.add(margin);
	}

	public static Currency getCurrency() {
		return currency;
	}

	public static void setCurrency(Currency currency) {
		AccountHolder.currency = currency;
	}
	
	/**
	 * Рассчитывает стоимость одного пункта в валюте <b>currency</b><br>
	 * Формулы:<br>
	 * <ol>
	 * <li>Порядок расчета стоимости пункта для валютной пары с прямой котировкой (XXX/USD) по <b>currency</b> (USD)<br>
	 * <b>contractSize * instrument.getPipValue() * lotSize</b>
	 * </li>
	 * <li>Порядок расчета стоимости пункта для валютной пары с обратной котировкой (USD/XXX) по <b>currency</b> (USD)<br>
	 * <b>contractSize * instrument.getPipValue() * lotSize / quotation</b>
	 * </li>
	 * <li>Порядок расчета стоимости пункта для кроссовой валютной пары (XXX/YYY) с прямой валютой котировки (YYY/USD) по отношению к <b>currency</b> (USD)<br>
	 * <b>contractSize * instrument.getPipValue() * lotSize * quotation2</b>
	 * </li>
	 * <li>Порядок расчета стоимости пункта для кроссовой валютной пары (XXX/YYY) с обратной валютой котировки (USD/YYY) по отношению к <b>currency</b> (USD)<br>
	 * <b>contractSize * instrument.getPipValue() * lotSize / quotation2</b>
	 * </li>
	 * </ol>
	 * 
	 * 
	 * @param currency - валюта, в которой ищем стоимость пункта
	 * @param contractSize - стандартный размер контракта (лота) в юнитах. Например для Dukascopy - миллион, для Alpari - сто тысяч
	 * @param instrument - инструмент на котором играем
	 * @param lotSize - размер сделки (в лотах)
	 * @param quotation - котировка инструмента <b>instrument</b>. Используеся в рассчётах, для пары с обратной котировкой по <b>currency</b>. Пункт 2 в описании
	 * @param instrument2 - инструмент, используемый для расчёта стоимости пункта для кроссовой валютной пары  (кросс-курса) с прямой/обратной валютой котировки по отношению к USD
	 * @param quotation2 - котировка инструмента <b>instrument2</b>. Пункт 3 и 4 в описании
	 * @return вычисленное значение, либо 0, если переданные параметры не позволили выполнить расчёт (переданные валютные пары не связаны общей валютой)
	 */
	public static double getPipSizeInCurrency(
			Currency currency, 
			int contractSize, 
			Instrument instrument, 
			double lotSize, 
			double quotation,
			Instrument instrument2,
			double quotation2){
		
		BigDecimal out = BigDecimal.ZERO;
		int scale = 0;
		
		BigDecimal base = new BigDecimal(contractSize).multiply(new BigDecimal(instrument.getPipValue())).multiply(new BigDecimal(lotSize));
		
		if(instrument.getSecondaryCurrency().equals(currency)){
			scale = instrument.getSecondaryCurrency().getDefaultFractionDigits();
			out = base.round(MC);
		}else if(instrument.getPrimaryCurrency().equals(currency)){
			scale = instrument.getPrimaryCurrency().getDefaultFractionDigits();
			out = base.divide(new BigDecimal(quotation)).round(MC);
		}else{
			if(instrument2.getSecondaryCurrency().equals(currency) && instrument2.getPrimaryCurrency().equals(instrument.getSecondaryCurrency())){
				scale = instrument.getSecondaryCurrency().getDefaultFractionDigits();
				out = base.multiply(new BigDecimal(quotation2)).round(MC);
			}else if(instrument2.getPrimaryCurrency().equals(currency) && instrument2.getSecondaryCurrency().equals(instrument.getSecondaryCurrency())){
				scale = instrument.getPrimaryCurrency().getDefaultFractionDigits();
				out = base.divide(new BigDecimal(quotation2)).round(MC);
			}
		}
		
		return out.setScale(scale, RoundingMode.HALF_UP).doubleValue();
	}
	
	/**
	 * Рассчитывает объём суммы, необходимой для игры на одной валютной паре из множества валютных пар колличеством <b>currenciesCount</b>.
	 * Формула: <b>balance * holdForOrdersPercentage / currenciesCount</b>
	 * @param balance
	 * @param holdForOrdersPercentage
	 * @param currenciesCount
	 * @return
	 */
	public static final BigDecimal calculateOrderHold(BigDecimal balance, BigDecimal holdForOrdersPercentage, BigDecimal currenciesCount){
		return balance.multiply(holdForOrdersPercentage, MC).divide(currenciesCount, MC);
	}

	/**
	 * Расчёт параметра X в формуле расчёта размера лота 
	 * @param type
	 * @param up
	 * @param startQoutation
	 * @param pointValue
	 * @param scale
	 * @param points
	 * @return
	 */
	public static final BigDecimal getPointsDynamicPriceSum(int type, boolean up, BigDecimal startQoutation, BigDecimal pointValue, int scale, BigDecimal points){
		BigDecimal out = BigDecimal.ZERO;
		
		switch(type){
			case 1:{
				out = points;
				break;
			}
			case 2:
			case 4:{
				out = BigDecimal.ONE.divide(startQoutation, MC);
				if(!up){
					startQoutation = startQoutation.add(pointValue.multiply(points.negate()));
				}
				for(BigDecimal i = BigDecimal.ONE; i.compareTo(points) < 1; i = i.add(BigDecimal.ONE)){
					out = out.add(BigDecimal.ONE.divide(startQoutation.add(pointValue.multiply(i)), MC));
				}
				break;
			}
			case 3:{
				out = startQoutation;
				if(!up){
					startQoutation = startQoutation.add(pointValue.multiply(points.negate()));
				}
				for(BigDecimal i = BigDecimal.ONE; i.compareTo(points) < 1; i = i.add(BigDecimal.ONE)){
					out = out.add(startQoutation.add(pointValue.multiply(i)));
				}
				break;
			}
		}
		return out.setScale(scale, RoundingMode.HALF_UP);
	}
	
	public static final BigDecimal getCalculatedLotSize(Instrument instrument){
		/*
    	IAccount account = ContextHolder.getContext().getAccount();
    	double leverage = account.getLeverage();
    	int margingCutLevel = account.getMarginCutLevel();
    	account.get
    	double balance = account.getBalance();
    	double equity = account.getEquity(); // Balance + Floating Profit/Loss
    	
    	BigDecimal balance = Consts.BALANCE_TO_RISK.compareTo(BigDecimal.ZERO) > 0 ? Consts.BALANCE_TO_RISK : new BigDecimal(account.getBalance());
    	BigDecimal leverage = new BigDecimal(account.getLeverage());
    	BigDecimal preOut = Consts.PERCENT_OF_BALANCE_TO_RISK.multiply(balance).multiply(leverage).divide(Consts.LOT_SIZE);
    	BigDecimal minAmount = getMinAmountForOrder();
    	BigDecimal out = preOut.compareTo(minAmount) < 0 ? minAmount : preOut;
    	logger.info("Calculated value or order: {}", out.doubleValue());
    	return out;
    	*/
		return getMinAmountForOrder(instrument);
	}
	
	public static final BigDecimal getBalanceForBusiness(){
		BigDecimal out = BigDecimal.ZERO;
		return out;
	}
	
	public static final BigDecimal getOrderHold(){
		BigDecimal out = BigDecimal.ZERO;
		return out;
	}
	
	public static final BigDecimal getMargin(){
		BigDecimal out = BigDecimal.ZERO;
		return out;
	}
	
	public static final BigDecimal getSpreadSum(){
		BigDecimal out = BigDecimal.ZERO;
		return out;
	}
	
	public static final BigDecimal getSLSum(){
		BigDecimal out = BigDecimal.ZERO;
		return out;
	}
	
	public static final int getSLPoints(){
		int out = 0;
		return out;
	}
	
	public static BigDecimal getMinAmountForOrder(Instrument instrument){
        switch (instrument){
            case XAUUSD : return new BigDecimal(0.000001);
            case XAGUSD : return new BigDecimal(0.00005);
            default : return new BigDecimal(0.001);
        }
    }
}
